﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Lucene.Net.Documents;
using Lucene.Net.Search;

namespace Lucene.Linq.Mapping
{
    /// <summary>
    /// ToDO: refactor to use DocumentDetails
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal class ObjectReader<T> : IEnumerable<T>
    {
        private Enumerator _enumerator;

        internal ObjectReader(Hits hits, DocumentDetails documentDetails)
        {
            _enumerator = new Enumerator(hits, documentDetails);
        }

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            Enumerator e = _enumerator;

            if (e == null)
            {
                throw new InvalidOperationException("Cannot enumerate more than once");
            }

            _enumerator = null;
            return e;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        #region Nested type: Enumerator

        private class Enumerator : IEnumerator<T>
        {
            private readonly DocumentDetails _documentDetails;
            private readonly Hits _hits;
            private T _current;
            private int _index;

            internal Enumerator(Hits hits, DocumentDetails documentDetails)
            {
                _hits = hits;
                _documentDetails = documentDetails;
            }

            #region IEnumerator<T> Members

            public T Current
            {
                get { return _current; }
            }

            object IEnumerator.Current
            {
                get { return _current; }
            }

            public bool MoveNext()
            {
                if (_index < _hits.Length())
                {
                    T instance = default(T); //TODO: change to activation
                    Document document = _hits.Doc(_index);

                    foreach (
                        FieldDetails fieldDetail in
                            _documentDetails.Fields.Where(fieldDetail => fieldDetail.Field.Store != Field.Store.NO))
                    {
                        fieldDetail.Property.SetValue(instance, document.GetField(fieldDetail.Name).StringValue(),
                                                      null);
                    }

                    _index++;
                    _current = instance;
                    return true;
                }

                return false;
            }

            public void Reset()
            {
            }

            public void Dispose()
            {
            }

            #endregion
        }

        #endregion
    }
}